/******************************************************************************
 * @file     Boot_Manager.c
 * @brief    Bootloader跳转相关函数
 * @author   Ruilist
 * @date     2025-08-15
 * @version  V1.0.0
 * @copyright Copyright (c) 2025
 *
 * @note     1 tab = 4 space
 *
 * @par 日志:
 * - V1.0.0 2025-08-15 Ruilist
 *****************************************************************************/

//******************************** Includes *********************************//

#include "Boot_Manager.h"

//******************************** Includes *********************************//

//******************************** Defines **********************************//

int32_t app_size_ymodem = 0;    // ymodem协议解析出的app大小
uint8_t Ymodem_rec[1024];       // ymodem接收缓存数组
uint8_t Mem_Read_buffer[4096];  // flash读出缓存

// AES密钥向量 16字节
//  IV[16]=RUILIST052500000

// AES密钥 32字节 AES-256
// KEY[32]=RUILIST052500000RUILIST052500000

unsigned char IV[16] =
    {
        0x52,
        0x55,
        0x49,
        0x4C,
        0x49,
        0x53,
        0x54,
        0x30,
        0x35,
        0x32,
        0x35,
        0x30,
        0x30,
        0x30,
        0x30,
        0x30 };

unsigned char KEY[32] =
    {
        0x52,
        0x55,
        0x49,
        0x4C,
        0x49,
        0x53,
        0x54,
        0x30,
        0x35,
        0x32,
        0x35,
        0x30,
        0x30,
        0x30,
        0x30,
        0x30,
        0x52,
        0x55,
        0x49,
        0x4C,
        0x49,
        0x53,
        0x54,
        0x30,
        0x35,
        0x32,
        0x35,
        0x30,
        0x30,
        0x30,
        0x30,
        0x30 };
//******************************** Defines **********************************//

//******************************** Declaring ********************************//

/**
 * @brief   跳转至APP运行区
 *
 * @param   void
 *
 * @return  void
 *
 */
void JumpToApp( void )
{
    /* 检查栈顶地址是否合法 */
    uint32_t  JumpAddress;
    pFunction Jump_To_Application;

    /* 检查栈顶地址是否合法 */
    if ( ( ( *(__IO uint32_t *)APPLICATION_ADDRESS ) & 0x2FFE0000 ) == 0x20000000 )
    {
        /* 屏蔽所有中断，防止在跳转过程中，中断干扰出现异常 */
        __disable_irq();
        NVIC_SetVectorTable( NVIC_VECT_TAB_FLASH, 0x8000 );
        RCC_DeInit();
        /* 用户代码区第二个 字 为程序开始地址(复位地址) */
        JumpAddress = *(__IO uint32_t *)( APPLICATION_ADDRESS + 4 );

        /* Initialize user application's Stack Pointer */
        /* 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) */
        __set_MSP( *(__IO uint32_t *)APPLICATION_ADDRESS );

        /* 类型转换 */
        Jump_To_Application = (pFunction)JumpAddress;

        /* 跳转到 APP */
        Jump_To_Application();
    }
}

/**
 * @brief   OTA状态机
 *
 * @param   void
 *
 * @return  void
 *
 */
void OTA_state_manager( void )
{
    uint8_t OTA_state = NO_APP_UPDATE;
    // uint32_t app_size  = 0; //当前APP大小
    int32_t file_size = 0;  // 新固件大小

    ee_ReadBytes( &OTA_state, 0x00, 1 );
    switch ( OTA_state )
    {
    case NO_APP_UPDATE:
        if ( Key_Scan() )
        {
            file_size = Ymodem_Receive( Ymodem_rec );
            log_d( "file_size is[%d]\r\n", file_size );
            if ( 0 == ExA_To_ExB_AES( file_size ) )
            {
                // 读当前App的大小
                // ee_ReadBytes( (uint8_t *)&app_size, 0x05, 4 );
                // App_To_ExA( app_size );

                ExB_To_App();
                JumpToApp();

                // ExA_To_App();
                // JumpToApp();
            }
            else
            {
                log_w( "Boot dowload failed\r\n" );
                JumpToApp();
            }
        }
        else
        {
            JumpToApp();
        }
        break;

    case APP_DOWNLOADING:
        log_w( "App dowload failed\r\n" );
        JumpToApp();
        log_a( "No Valid App\r\n" );
        file_size = Ymodem_Receive( Ymodem_rec );

        if ( 0 == ExA_To_ExB_AES( file_size ) )
        {
            // 读当前App的大小
            // ee_ReadBytes( (uint8_t *)&app_size, 0x05, 4 );
            // App_To_ExA( app_size );

            ExB_To_App();
            JumpToApp();

            // ExA_To_App();
            // JumpToApp();
        }
        else
        {
            log_w( "Boot dowload failed" );
            JumpToApp();
        }
        break;

    case APP_DOWNLOAD_COMPLETE:

        ee_ReadBytes( (uint8_t *)&file_size, 0x01, 4 );
        log_d( "ee_ReadBytes ok appsize is[%d]\r\n", file_size );
        // App大小更新到内部flash存储数据量的管理结构体中
        SetBlockParmeter( BLOCK_1, file_size );
        if ( 0 == ExA_To_ExB_AES( file_size ) )
        {
            // 读当前App的大小
            // ee_ReadBytes( (uint8_t *)&app_size, 0x05, 4 );
            // App_To_ExA( app_size );

            ExB_To_App();
            JumpToApp();

            // ExA_To_App();
            // JumpToApp();
        }
        else
        {
            log_w( "Boot dowload failed\r\n" );
            JumpToApp();
        }
        break;
    default:
        break;
    }
}

/**
 * @brief 外部flashA区中数据拷贝到App区中
 *
 * @param None
 *
 * @return: The status of the initialization.
 */
int8_t ExA_To_App( void )
{
    uint32_t FlashDes        = APPLICATION_ADDRESS;
    uint32_t flashsize       = 0;
    uint8_t  Read_dataState  = 0;
    uint16_t Read_Memorysize = 0;
    uint32_t RamSource       = 0;
    uint16_t writeTime       = 0;
    /*擦除本地flash数据*/
    flashsize = Read_BlockSize( BLOCK_1 );
    if ( 1 == Flash_erase( FlashDes, flashsize ) )
    {
        return -1;
    }
    else
    {
        for ( ;; )
        {
            Read_dataState = W25Q64_ReadData( BLOCK_1, Mem_Read_buffer, &Read_Memorysize );
            if ( 1 == Read_dataState )
            {
                // 数据读完退出
                break;
            }
            else if ( 2 == Read_dataState )
            {
                // 外部flash数据读取有问题
                break;
            }
            else
            {
                // ramsource指向缓冲区的地址
                RamSource = (uint32_t)Mem_Read_buffer;
                // 循环搬运flash数据
                for ( writeTime = 0; writeTime < ( Read_Memorysize / 4 ); writeTime++ )
                {
                    // Read_Memorysize是读取到的数据大小，除以4个字节为要循环写入的次数
                    Flash_Write( FlashDes, *(uint32_t *)RamSource );
                    FlashDes += 4;
                    RamSource += 4;
                }
            }
        }
        return flashsize;
    }
}

/**
 * @brief 外部flashB区中数据拷贝到APP区中
 *
 * @param None
 *
 * @return: The status of the initialization.
 */
uint32_t ExB_To_App( void )
{
    uint32_t FlashDes        = APPLICATION_ADDRESS;
    uint32_t flashsize       = 0;
    uint8_t  Read_dataState  = 0;
    uint16_t Read_Memorysize = 0;
    uint32_t RamSource       = 0;
    uint16_t writeTime       = 0;
    /*擦除本地flash数据*/
    flashsize = Read_BlockSize( BLOCK_2 );
    if ( 1 == Flash_erase( FlashDes, flashsize ) )
    {
        return 0;
    }
    else
    {
        for ( ;; )
        {
            Read_dataState = W25Q64_ReadData( BLOCK_2, Mem_Read_buffer, &Read_Memorysize );
            if ( 1 == Read_dataState )
            {
                // 数据读完退出
                break;
            }
            else if ( 2 == Read_dataState )
            {
                // 外部flash数据读取有问题
                break;
            }
            else
            {
                RamSource = (uint32_t)Mem_Read_buffer;
                // 循环搬运flash数据
                for ( writeTime = 0; writeTime < ( Read_Memorysize / 4 ); writeTime++ )
                {
                    // Flash_Write(FlashDes,RamSource);//Old
                    Flash_Write( FlashDes, *(uint32_t *)RamSource );
                    FlashDes += 4;
                    RamSource += 4;
                }
            }
        }
        return flashsize;
    }
}

/**
 * @brief app区数据拷贝到外部flashA区中
 *
 * @param None
 *
 * @return: The status of the initialization.
 */
int8_t App_To_ExA( int32_t fl_size )
{
    uint32_t FlashDes = APPLICATION_ADDRESS;
    if ( ( fl_size > ( 0x18010 - 1 ) ) ||
         ( fl_size < 0 ) )
    {
        return -1;
    }

    Erase_Flash_Block( BLOCK_1 );
    W25Q64_WriteData( BLOCK_1, (uint8_t *)FlashDes, fl_size );
    W25Q64_WriteData_End( BLOCK_1 );
    return 0;
}

/**
 * @brief 外部flashA区数据解密拷贝到外部flashB区中
 *
 * @param None
 *
 * @return: The status of the initialization.
 */
int8_t ExA_To_ExB_AES( int32_t fl_size )
{
    uint8_t  Temp[16];                         // 原密文数据缓存
    uint16_t readTime = 0, readDataCount = 0;  // 读取数据再解密的次数（每次解密16个字节）
    uint32_t AppSize = 0;                      // 升级包的大小
    // uint32_t FlashDestination=APPLICATION_ADDRESS;
    uint16_t Read_Memory_Size   = 0;
    uint32_t Read_Memory_index  = 0;
    uint8_t *puint8_t_IV_IN_OUT = IV;
    uint8_t *puint8_t_key256bit = KEY;
    if ( fl_size <= 0 )
    {
        return -1;
    }
    if ( ( app_size_ymodem > ( 0x18010 - 1 ) ) ||
         ( app_size_ymodem < 0 ) )
    {
        return -1;
    }
    // 先读一帧，用来解析头文件格式
    W25Q64_ReadData( BLOCK_1, Mem_Read_buffer, &Read_Memory_Size );
    if ( Read_Memory_Size >= 16 )
    {
        memcpy( Temp, Mem_Read_buffer, 16 );
        Aes_IV_key256bit_Decode( puint8_t_IV_IN_OUT, Temp, puint8_t_key256bit );  // 解析得到自定义内容+文件大小
        AppSize = ( Temp[15] << 24 ) + ( Temp[14] << 16 ) + ( Temp[13] << 8 ) + Temp[12];
        log_d( "AppSize=%d", AppSize );
        // 计算升级包读取次数
        readDataCount = AppSize / 16;
        if ( AppSize % 16 != 0 )
        {
            readDataCount += 1;
        }
        Read_Memory_index += 16;
    }
    else
    {
        return -1;
    }

    // 擦除外部flash比较耗时
    for ( readTime = 0; readTime < readDataCount; readTime++ )
    {
        // 判断下当前buffer下的数据是否读取完毕
        if ( Read_Memory_index == Read_Memory_Size )
        {
            if ( 2 == W25Q64_ReadData( BLOCK_1, Mem_Read_buffer, &Read_Memory_Size ) )
            {
                log_d( "Write_Flash_After_AES_Decode read extern buffer error" );
                return -1;
            }
            Read_Memory_index = 0;
        }
        // 拷贝16个数据
        memcpy( Temp, Mem_Read_buffer + Read_Memory_index, 16 );
        Read_Memory_index += 16;
        // 解析16个数据
        Aes_IV_key256bit_Decode( puint8_t_IV_IN_OUT, Temp, puint8_t_key256bit );  // 解析

        W25Q64_WriteData( BLOCK_2, Temp, 16 );
    }
    W25Q64_WriteData_End( BLOCK_2 );
    log_d( "Write_Flash_After_AES_Decode end" );
    return 0;
}

//******************************** Declaring ********************************//
